#include "DXDrawInterface.h"
#include "DXGlobal.h"
#include "GetDirectDraw.h"
#include "GpTool.h"

#pragma comment(lib,"GraphicShare.lib")

IDXDirectDraw*	g_pkDXDirectDraw = NULL;
IDXBitmap*		g_pkDXBitmap = NULL;

bool DDrawInit(HWND hWnd,int iWidth,int iHeight,int iBpp,bool bFullScreen)
{
	g_lpDirectDraw = GetDirectDraw();
	if(!g_lpDirectDraw)
	{
		return false;
	}

	g_pkDXDirectDraw = new DXDirectDraw;
	if(!g_pkDXDirectDraw)
	{
		return false;
	}

	g_pkDXBitmap = new DXBitmap;
	if(!g_pkDXBitmap)
	{
		return false;
	}

	g_hWnd = hWnd;
	g_iWidth = iWidth;
	g_iHeight = iHeight;
	g_iBpp = iBpp;

	if(bFullScreen)
	{
		if(FAILED(g_lpDirectDraw->SetCooperativeLevel(hWnd,DDSCL_FULLSCREEN|
			DDSCL_ALLOWMODEX|
			DDSCL_EXCLUSIVE|
			DDSCL_ALLOWREBOOT|
			DDSCL_MULTITHREADED)))
		{
			return false;
		}
	}
	else
	{
		if(FAILED(g_lpDirectDraw->SetCooperativeLevel(hWnd,DDSCL_NORMAL)))
		{
			return false;
		}
	}

	if(FAILED(g_lpDirectDraw->SetDisplayMode(g_iWidth,g_iHeight,g_iBpp,0,0)))
	{
		return false;
	}

	if(bFullScreen)
	{
		g_lpDDSurfacePrimary = GetDirectDrawSurface(g_lpDirectDraw,bFullScreen);
		if(!g_lpDDSurfacePrimary)
		{
			return false;
		}

		g_lpDDSurfaceBack = GetDirectDrawSurfaceBack(g_lpDDSurfacePrimary);
		if(!g_lpDDSurfaceBack)
		{
			return false;
		}
	}
	else
	{
		g_lpDDSurfacePrimary = GetDirectDrawSurface(g_lpDirectDraw,bFullScreen);
		if(!g_lpDDSurfacePrimary)
		{
			return false;
		}
	}

	return true;
}

bool DDrawFinalize(void)
{
	SALF_DELETE(g_pkDXDirectDraw);
	SALF_DELETE(g_pkDXBitmap);

	ReleaseDirectDraw(g_lpDirectDraw);
	ReleaseDirectDrawSurface(g_lpDDSurfacePrimary);
	ReleaseDirectDrawClipper(g_lpDDClipper);
	ReleaseDirectDrawPalette(g_lpDDPalette);

	return true;
}

// DXDirectDraw  ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
DXDirectDraw::~DXDirectDraw()
{

}

LPDIRECTDRAWSURFACE7 DXDirectDraw::DDrawCreateSurface(int iWidth,int iHeight,int iMemFlag)
{
	if(!g_lpDirectDraw)
	{
		return NULL;
	}

	return DirectDrawCreateSurface(g_lpDirectDraw,iWidth,iHeight,iMemFlag);
}

int DXDirectDraw::DrawTextGDI(const WCHAR* acText,int iX,int iY,COLORREF Color)
{
	if(!g_lpDDSurfacePrimary)
	{
		return NULL;
	}

	return DirectDrawTextGDI(acText,iX,iY,Color,g_lpDDSurfacePrimary);
}

bool DXDirectDraw::RendBitMap(BITMAPFILEPTR pkBitMap)
{
	if(!g_pkDXDirectDraw)
	{
		return false;
	}

	LPDIRECTDRAWSURFACE7 lpVideoSurface = NULL;
	lpVideoSurface = DDrawCreateSurface(pkBitMap->kBitInfoHeader.biWidth,pkBitMap->kBitInfoHeader.biHeight,DDSCAPS_VIDEOMEMORY);
	if(!lpVideoSurface)
	{
		return false;
	}
	
	int iPitch = 0;
	UINT* pkVideoBuffer = DDrawLockSurface(lpVideoSurface,iPitch);
	
	for(int iX = 0;iX < pkBitMap->kBitInfoHeader.biWidth;++iX)
	{
		for(int iY = 0;iY < pkBitMap->kBitInfoHeader.biHeight;++iY)
		{
			UCHAR ucBlue = (pkBitMap->pcBuffer[iX * 3 + iY * pkBitMap->kBitInfoHeader.biWidth * 3 + 0]);
			UCHAR ucGreen = (pkBitMap->pcBuffer[iX * 3 + iY * pkBitMap->kBitInfoHeader.biWidth * 3 + 1]);
			UCHAR ucRed = (pkBitMap->pcBuffer[iX * 3 + iY * pkBitMap->kBitInfoHeader.biWidth * 3 + 2]);

			PlotPixel_Fast32(iX,iY,0,ucRed,ucGreen,ucBlue,pkVideoBuffer,iPitch);
		}
	}
	DDrawUnlockSurface(lpVideoSurface);

	RECT kSourceRect,kDestRect;
	kDestRect.left = 0;
	kDestRect.top = 0;
	kDestRect.right = pkBitMap->kBitInfoHeader.biWidth;
	kDestRect.bottom = pkBitMap->kBitInfoHeader.biHeight;

	kSourceRect.left = 0;
	kSourceRect.top = 0;
	kSourceRect.right = pkBitMap->kBitInfoHeader.biWidth;
	kSourceRect.bottom = pkBitMap->kBitInfoHeader.biHeight;

	if(g_lpDDSurfaceBack)
	{
		if(FAILED(g_lpDDSurfaceBack->Blt(&kDestRect,lpVideoSurface,&kSourceRect,DDBLT_WAIT|DDBLT_KEYSRC,NULL)))
		{
			lpVideoSurface->Release();
			return false;
		}
	}

	if(FAILED(g_lpDDSurfacePrimary->Flip(NULL,DDFLIP_WAIT)))
	{
		MyOutputDebugString(TEXT("Primary Flip Fail\n"));
		lpVideoSurface->Release();
		return false;
	}

	lpVideoSurface->Release();
	return true;
}

void DXDirectDraw::PlotPixel_Fast16(int iX,int iY,int iRed,int iGreen,int iBlue,
	USHORT* pkVideoBuffer,int iPitch)
{
	USHORT pixel = RGB16BIT565(iRed,iGreen,iBlue);
	pkVideoBuffer[iX + iY * iPitch] = pixel;
}

void DXDirectDraw::PlotPixel_Fast24(int iX,int iY,int iRed,int iGreen,int iBlue,
	UCHAR* pkVideoBuffer,int iPitch)
{
	DWORD dwPixelAddr = (iX + iX + iX) + iY * iPitch;
	pkVideoBuffer[dwPixelAddr] = iBlue;
	pkVideoBuffer[dwPixelAddr + 1] = iGreen;
	pkVideoBuffer[dwPixelAddr + 2] = iRed;
}

void DXDirectDraw::PlotPixel_Fast32(int iX,int iY,int iAlpha,int iRed,int iGreen,int iBlue,
	UINT* pkVideoBuffer,int iPitch)
{
	UINT uiPixel = RGB32BIT(iAlpha,iRed,iGreen,iBlue);
	pkVideoBuffer[iX + iY * iPitch] = uiPixel;
}

void DXDirectDraw::GetVidCapMomery(DWORD& dwTotal,DWORD& dwFree)
{
	if(!g_lpDirectDraw)
	{
		return;
	}

	DDCAPS kHalCaps;
	DDRAW_INIT_STRUCT(kHalCaps);
	g_lpDirectDraw->GetCaps(&kHalCaps,NULL);

	dwTotal = kHalCaps.dwVidMemTotal / 1024 / 1024;
	dwFree = kHalCaps.dwVidMemFree / 1024 / 1024;
}

void DXDirectDraw::GetVideoMomery(DWORD& dwTotal,DWORD& dwFree)
{
	if(!g_lpDirectDraw)
	{
		return;
	}

	DDSCAPS2 kScaps2;
	memset(&kScaps2,0,sizeof(kScaps2));

	kScaps2.dwCaps2 = DDSCAPS_VIDEOMEMORY;

	DWORD dwScapsTotal = 0;
	DWORD dwScapsFree = 0;
	g_lpDirectDraw->GetAvailableVidMem(&kScaps2,&dwScapsTotal,&dwScapsFree);
	dwTotal = dwScapsTotal / 1024 / 1024;
	dwFree = dwScapsFree / 1024 / 1024;
}

// ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== =====

// DXBitmap  ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== 
DXBitmap::~DXBitmap()
{
	if(!m_kVBitmapFilePtr.empty())
	{
		for(size_t i = 0;i < m_kVBitmapFilePtr.size();++i)
		{
			BITMAPFILEPTR pkBitMapPtr = m_kVBitmapFilePtr[i];
			SALF_DELETE(pkBitMapPtr);
		}
	}
	m_kVBitmapFilePtr.clear();
}

BITMAPFILEPTR DXBitmap::CreateBitMap(const char* pcFileName)
{
	BITMAPFILEPTR pkBitMapPtr = new BITMAPFILE;
	if(!pkBitMapPtr)
	{
		return NULL;
	}

	LoadBitMapFile(pkBitMapPtr,pcFileName);
	if(!pkBitMapPtr)
	{
		return NULL;
	}

	m_kVBitmapFilePtr.push_back(pkBitMapPtr);
	return pkBitMapPtr;
}

bool DXBitmap::ReleaseBitMap(BITMAPFILEPTR& pkBitMap)
{
	UnloadBitMapFile(pkBitMap);
	SALF_DELETE(pkBitMap);
	return true;
}
